import type {RouterProps} from 'react-router'
import type {
  commitMutation,
  MutationParameters,
  RecordProxy,
  RecordSourceSelectorProxy
} from 'relay-runtime'
import type Atmosphere from '../Atmosphere'

export type CompletedHandler<TResponse = any> = (
  response: TResponse,
  errors?: readonly any[] | null
) => void

export type ErrorHandler = (error: Error) => void

/* DEPRECATED, use BaseLocalHandlers+ */
export interface LocalHandlers {
  onError?: ErrorHandler
  onCompleted?: CompletedHandler
  history?: RouterProps['history']
}

export interface BaseLocalHandlers {
  onError: ErrorHandler
  onCompleted: CompletedHandler
}

export interface HistoryLocalHandler extends BaseLocalHandlers {
  history: RouterProps['history']
}

export interface HistoryMaybeLocalHandler {
  history: RouterProps['history']
  onError?: ErrorHandler
  onCompleted?: CompletedHandler
}

export type OptionalHandlers = Partial<BaseLocalHandlers>

interface UpdaterContext {
  atmosphere: Atmosphere
  // can't assume store<Parent> == store<Child>, so no generics can be used here
  store: RecordSourceSelectorProxy
}

export type SharedUpdater<T> = (
  payload: RecordProxy<Omit<NonNullable<T>, ' $fragmentType'>>,
  context: UpdaterContext
) => void

export interface OnNextBaseContext {
  atmosphere: Atmosphere
}

export interface OnNextHistoryContext extends OnNextBaseContext {
  history: RouterProps['history']
}

export type OnNextHandler<TSubResponse, C = OnNextBaseContext> = (
  payload: null extends TSubResponse
    ? Omit<NonNullable<TSubResponse>, ' $fragmentType'> | null
    : undefined extends TSubResponse
      ? Omit<NonNullable<TSubResponse>, ' $fragmentType'> | undefined
      : Omit<TSubResponse, ' $fragmentType'>,
  context: C
) => void

export type SimpleMutation<T extends MutationParameters> = (
  atmosphere: Atmosphere,
  variables: T['variables']
) => ReturnType<typeof commitMutation> | undefined
export type StandardMutation<T extends MutationParameters, C = BaseLocalHandlers> = (
  atmosphere: Atmosphere,
  variables: T['variables'],
  localHandlers: C
) => ReturnType<typeof commitMutation>

export type RelayDateHack<T extends {variables: any}, P> = Omit<T, 'variables'> & {
  variables: Omit<T['variables'], keyof P> & P
}
